package com.xyht.medicine_management_system.modules.stock.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xyht.medicine_management_system.common.commonReturn.CommonCodeEnum;
import com.xyht.medicine_management_system.common.commonReturn.CommonResult;
import com.xyht.medicine_management_system.common.commonReturn.ResponseResult;
import com.xyht.medicine_management_system.common.util.ApiModelUtil;
import com.xyht.medicine_management_system.common.util.TimeUtil;
import com.xyht.medicine_management_system.modules.classification.entity.MmsMedicineClassification;
import com.xyht.medicine_management_system.modules.classification.mapper.MmsMedicineClassificationMapper;
import com.xyht.medicine_management_system.modules.common.entity.MmsImportTask;
import com.xyht.medicine_management_system.modules.common.entity.MmsImportTaskDetail;
import com.xyht.medicine_management_system.modules.common.mapper.MmsImportTaskDetailMapper;
import com.xyht.medicine_management_system.modules.common.mapper.MmsImportTaskMapper;
import com.xyht.medicine_management_system.modules.medicine.entity.MmsMedicine;
import com.xyht.medicine_management_system.modules.medicine.entity.resp.MmsMedicineClassificationResp;
import com.xyht.medicine_management_system.modules.medicine.entity.resp.MmsMedicineDetailResp;
import com.xyht.medicine_management_system.modules.medicine.entity.resp.MmsMedicineUserResp;
import com.xyht.medicine_management_system.modules.medicine.mapper.MmsMedicineMapper;
import com.xyht.medicine_management_system.modules.stock.entity.MmsMedicineStock;
import com.xyht.medicine_management_system.modules.stock.entity.MmsMedicineStockLog;
import com.xyht.medicine_management_system.modules.stock.entity.req.*;
import com.xyht.medicine_management_system.modules.stock.entity.resp.MmsMedicineStockDetailResp;
import com.xyht.medicine_management_system.modules.stock.entity.resp.MmsMedicineStockExportResp;
import com.xyht.medicine_management_system.modules.stock.mapper.MmsMedicineStockLogMapper;
import com.xyht.medicine_management_system.modules.stock.mapper.MmsMedicineStockMapper;
import com.xyht.medicine_management_system.modules.stock.service.MmsMedicineStockService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xyht.medicine_management_system.modules.stock.util.MedicineStockUtil;
import com.xyht.medicine_management_system.modules.user.entity.MmsUser;
import com.xyht.medicine_management_system.modules.user.mapper.MmsUserMapper;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.medicine_management_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.medicine_management_system.modules.common.constant.SheetCommonConstant.PER_SHEET_NUM;
import static com.xyht.medicine_management_system.modules.common.constant.TaskDetailReason.*;
import static com.xyht.medicine_management_system.modules.common.constant.TaskNameExample.TASK_NAME_MEDICINE_STOCK_IMPORT;
import static com.xyht.medicine_management_system.modules.common.constant.TaskStatus.TASK_STATUS_DONE;
import static com.xyht.medicine_management_system.modules.common.constant.TaskStatus.TASK_STATUS_ERR;
import static com.xyht.medicine_management_system.modules.common.constant.TaskTypeConstant.TASK_TYPE_MEDICINE_STOCK;
import static com.xyht.medicine_management_system.modules.stock.constant.StockFlag.STOCK_NORMAL;
import static com.xyht.medicine_management_system.modules.stock.constant.StockType.STOCK_IN;
import static com.xyht.medicine_management_system.modules.stock.constant.StockType.STOCK_OUT;

/**
 * <p>
 * 药品库存 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2023-11-30
 */
@Service
public class MmsMedicineStockServiceImpl extends ServiceImpl<MmsMedicineStockMapper, MmsMedicineStock> implements MmsMedicineStockService {

    @Resource
    private MmsMedicineStockMapper medicineStockMapper;
    @Resource
    private MmsMedicineStockLogMapper medicineStockLogMapper;
    @Resource
    private MmsMedicineMapper medicineMapper;
    @Resource
    private MmsUserMapper userMapper;
    @Resource
    private MmsMedicineClassificationMapper medicineClassificationMapper;
    @Resource
    private MedicineStockUtil medicineStockUtil;
    @Resource
    private ApiModelUtil apiModelUtil;
    @Resource
    private MmsImportTaskMapper mmsImportTaskMapper;
    @Resource
    private MmsImportTaskDetailMapper mmsImportTaskDetailMapper;
    @Resource
    PlatformTransactionManager transactionManager;


    @Override
    @Transactional
    public ResponseResult addMedicineStock(MmsMedicineStockAddReq addReq, String userId) {
        if (isNullOrEmpty(addReq.getMedicineId(),addReq.getStockQuantity(),addReq.getMedicineUnit(),addReq.getStockType(),addReq.getInspectionReport())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        MmsMedicine medicine = medicineMapper.selectById(addReq.getMedicineId());
        if (isNullOrEmpty(medicine)) {
            return CommonResult.failed(CommonCodeEnum.MEDICINE_NOT_EXIST);
        }

        List<MmsMedicineStock> stockList = medicineStockMapper.selectList(new LambdaQueryWrapper<MmsMedicineStock>()
                .eq(MmsMedicineStock::getMedicineId, addReq.getMedicineId()));

        if (stockList != null && stockList.size() > 0) {
            return CommonResult.failed(CommonCodeEnum.MEDICINE_STOCK_REPEAT);
        }

        //新增库存
        MmsMedicineStock addMedicineStock = new MmsMedicineStock();
        BeanUtils.copyProperties(addReq,addMedicineStock);
        addMedicineStock.setUserId(userId);
        medicineStockMapper.insert(addMedicineStock);

        //新增库存历史
        Integer stockType = addReq.getStockType();//状态(1:入库 2:出库)

        MmsMedicineStockLog addMedicineStockLog = new MmsMedicineStockLog();
        addMedicineStockLog.setStockId(addMedicineStock.getId());
        addMedicineStockLog.setStockType(stockType);
        addMedicineStockLog.setMedicineName(medicine.getCommonNames());
        addMedicineStockLog.setMedicineCode(medicine.getMedicineCode());
        addMedicineStockLog.setRemarks(addReq.getRemarks());
        addMedicineStockLog.setUserId(userId);
        addMedicineStockLog.setStockFlag(STOCK_NORMAL);
        //入库
        if (addReq.getStockType() == STOCK_IN) {
            addMedicineStockLog.setIncomeDate(new Date());
            addMedicineStockLog.setIncomeQuantity(addReq.getStockQuantity());
            //出库
        } else if (addReq.getStockType() == STOCK_OUT) {
            addMedicineStockLog.setOutDate(new Date());
            addMedicineStockLog.setOutQuantity(addReq.getStockQuantity());
        }

        medicineStockLogMapper.insert(addMedicineStockLog);
        return CommonResult.success();
    }

    @Override
    @Transactional
    public ResponseResult updateMedicineStock(MmsMedicineStockUpdateReq updateReq, String userId) {
        if (isNullOrEmpty(updateReq.getMedicineId(),updateReq.getId(),updateReq.getStockQuantity())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //查看药品信息
        MmsMedicine medicine = medicineMapper.selectById(updateReq.getMedicineId());
        if (isNullOrEmpty(medicine)) {
            return CommonResult.failed(CommonCodeEnum.MEDICINE_NOT_EXIST);
        }
        //查看库存信息
        MmsMedicineStock medicineStock = medicineStockMapper.selectById(updateReq.getId());
        if (isNullOrEmpty(medicineStock)) {
            return CommonResult.failed(CommonCodeEnum.MEDICINE_STOCK_NOT_EXIST);
        }
        if (updateReq.getStockQuantity() < 0) {
            return CommonResult.failed(CommonCodeEnum.MEDICINE_STOCK_NOT_NEGATIVE);
        }
        BeanUtils.copyProperties(updateReq,medicineStock);

        medicineStockMapper.updateById(medicineStock);

        //新增库存历史
        Integer stockType = updateReq.getStockType();//状态(1:入库 2:出库)
        MmsMedicineStockLog addMedicineStockLog = new MmsMedicineStockLog();
        BeanUtils.copyProperties(updateReq,addMedicineStockLog,"id");
        addMedicineStockLog.setStockId(updateReq.getId());
        addMedicineStockLog.setStockType(stockType);
        addMedicineStockLog.setMedicineName(medicine.getCommonNames());
        addMedicineStockLog.setMedicineCode(medicine.getMedicineCode());
        addMedicineStockLog.setStockFlag(STOCK_NORMAL);
        addMedicineStockLog.setRemarks(updateReq.getRemarks());
        addMedicineStockLog.setUserId(userId);

        //入库
        if (updateReq.getStockType() == STOCK_IN) {
            addMedicineStockLog.setIncomeDate(new Date());
            addMedicineStockLog.setIncomeQuantity(updateReq.getStockQuantity());
            //出库
        } else if (updateReq.getStockType() == STOCK_OUT) {
            addMedicineStockLog.setOutDate(new Date());
            addMedicineStockLog.setOutQuantity(updateReq.getStockQuantity());
        }

        medicineStockLogMapper.insert(addMedicineStockLog);
        return CommonResult.success();
    }

    @Override
    public ResponseResult increaseMedicineStock(MmsMedicineStockIncreaseReq increaseReq, String userId) {
        medicineStockUtil.increaseMedicineStock(increaseReq.getId(),increaseReq.getMedicineId(), increaseReq.getIncreaseQuantity(), userId);
        return CommonResult.success();
    }

    @Override
    public ResponseResult reduceMedicineStock(MmsMedicineStockReduceReq reduceReq, String userId) {
        medicineStockUtil.reduceMedicineStock(reduceReq.getId(),reduceReq.getMedicineId(),reduceReq.getReduceQuantity(),userId);
        return CommonResult.success();
    }

    @Override
    public ResponseResult deletedMedicineStock(MmsMedicineStockDeletedReq deletedReq) {
        if (isNullOrEmpty(deletedReq.getId())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        MmsMedicineStock medicineStock = medicineStockMapper.selectById(deletedReq.getId());
        if (isNullOrEmpty(medicineStock)) {
            return CommonResult.failed(CommonCodeEnum.MEDICINE_STOCK_NOT_EXIST);
        }

        medicineStockMapper.deleteById(deletedReq.getId());
        return CommonResult.success();
    }

    @Override
    public ResponseResult getMedicineStockDetail(String id) {
        if (isNullOrEmpty(id)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        MmsMedicineStockDetailResp medicineStockDetailResp = new MmsMedicineStockDetailResp();
        MmsMedicineStock medicineStock = medicineStockMapper.selectById(id);
        if (isNullOrEmpty(medicineStock)) {
            return CommonResult.failed(CommonCodeEnum.MEDICINE_STOCK_NOT_EXIST);
        }
        BeanUtils.copyProperties(medicineStock, medicineStockDetailResp);

        //药品信息
        List<MmsMedicine> mmsMedicines = medicineMapper.selectList(new LambdaQueryWrapper<MmsMedicine>()
                .eq(MmsMedicine::getId, medicineStock.getMedicineId()));
        if (mmsMedicines.isEmpty()) {
            return CommonResult.failed(CommonCodeEnum.MEDICINE_NOT_EXIST);
        }
        MmsMedicineDetailResp medicineDetailResp = new MmsMedicineDetailResp();
        BeanUtils.copyProperties(mmsMedicines.get(0), medicineDetailResp);

        //分类
        MmsMedicineClassification medicineClassification = medicineClassificationMapper.selectById(mmsMedicines.get(0).getClassificationId());
        if (!isNullOrEmpty(medicineClassification)) {
            MmsMedicineClassificationResp classificationResp = new MmsMedicineClassificationResp();
            BeanUtils.copyProperties(medicineClassification,classificationResp);
            medicineDetailResp.setClassificationInfo(classificationResp);
        }
        medicineStockDetailResp.setMedicineDetailResp(medicineDetailResp);

        //创建人信息
        MmsUser user = userMapper.selectById(medicineStock.getUserId());
        if (!isNullOrEmpty(user)) {
            MmsMedicineUserResp userResp = new MmsMedicineUserResp();
            BeanUtils.copyProperties(user, userResp);
            medicineStockDetailResp.setUserInfo(userResp);
        }

        return CommonResult.success(medicineStockDetailResp);
    }

    @Override
    public ResponseResult getMedicineStockList(Integer pageNum, Integer pageSize, String searchStr, String startDate, String endDate) {
        Page<MmsMedicineStock> page = new Page<>(pageNum,pageSize);
        LambdaQueryWrapper<MmsMedicineStock> stockLambdaQueryWrapper = new LambdaQueryWrapper<MmsMedicineStock>().orderByDesc(MmsMedicineStock::getCreateTime);

        if (!isNullOrEmpty(searchStr)) {
            List<MmsMedicine> medicineList = medicineMapper.selectList(new LambdaQueryWrapper<MmsMedicine>()
                    .like(MmsMedicine::getCommonNames, searchStr)
                    .or()
                    .like(MmsMedicine::getMedicineCode, searchStr));
            if (!medicineList.isEmpty()) {
                List<String> medicineIdList = medicineList.stream().map(MmsMedicine::getId).collect(Collectors.toList());
                if (!medicineIdList.isEmpty()) {
                    stockLambdaQueryWrapper.in(MmsMedicineStock::getMedicineId, medicineIdList);
                } else {
                    stockLambdaQueryWrapper.in(MmsMedicineStock::getMedicineId, "");
                }

            } else {
                stockLambdaQueryWrapper.in(MmsMedicineStock::getMedicineId, "");
            }
        }
        if (!isNullOrEmpty(startDate)) {
            stockLambdaQueryWrapper.ge(MmsMedicineStock::getCreateTime,startDate);
        }
        if (!isNullOrEmpty(endDate)) {
            stockLambdaQueryWrapper.le(MmsMedicineStock::getUpdateTime,endDate);
        }


        medicineStockMapper.selectPage(page,stockLambdaQueryWrapper);
        List<MmsMedicineStockDetailResp> stockDetailList = page.getRecords()
                .stream()
                .map(mmsMedicineStock -> {
                    MmsMedicineStockDetailResp medicineStockDetailResp = new MmsMedicineStockDetailResp();
                    BeanUtils.copyProperties(mmsMedicineStock, medicineStockDetailResp);

                    //药品信息
                    List<MmsMedicine> mmsMedicines = medicineMapper.selectList(new LambdaQueryWrapper<MmsMedicine>()
                            .eq(MmsMedicine::getId, mmsMedicineStock.getMedicineId()));
                    if (!mmsMedicines.isEmpty()) {
                        MmsMedicineDetailResp medicineDetailResp = new MmsMedicineDetailResp();
                        BeanUtils.copyProperties(mmsMedicines.get(0), medicineDetailResp);

                        //分类
                        MmsMedicineClassification medicineClassification = medicineClassificationMapper.selectById(mmsMedicines.get(0).getClassificationId());
                        if (!isNullOrEmpty(medicineClassification)) {
                            MmsMedicineClassificationResp classificationResp = new MmsMedicineClassificationResp();
                            BeanUtils.copyProperties(medicineClassification,classificationResp);
                            medicineDetailResp.setClassificationInfo(classificationResp);
                        }
                        medicineStockDetailResp.setMedicineDetailResp(medicineDetailResp);
                    }

                    //创建人信息
                    MmsUser user = userMapper.selectById(mmsMedicineStock.getUserId());
                    if (!isNullOrEmpty(user)) {
                        MmsMedicineUserResp userResp = new MmsMedicineUserResp();
                        BeanUtils.copyProperties(user, userResp);
                        medicineStockDetailResp.setUserInfo(userResp);
                    }
                    return medicineStockDetailResp;
                })
                .collect(Collectors.toList());
        int total = (int) page.getTotal();
        return CommonResult.success(stockDetailList,total);
    }

    @Override
    public ResponseResult getMedicineStockHistoryList(Integer pageNum, Integer pageSize, String searchStr, String startDate, String endDate,
                                                      Integer stockType, String stockId) {
        Page<MmsMedicineStockLog> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<MmsMedicineStockLog> stockLambdaQueryWrapper = new LambdaQueryWrapper<MmsMedicineStockLog>().orderByDesc(MmsMedicineStockLog::getCreateTime);

        if (!isNullOrEmpty(searchStr)) {
            List<MmsMedicine> medicineList = medicineMapper.selectList(new LambdaQueryWrapper<MmsMedicine>()
                    .like(MmsMedicine::getCommonNames, searchStr)
                    .or()
                    .like(MmsMedicine::getMedicineCode, searchStr));
            if (!medicineList.isEmpty()) {
                List<String> medicineIdList = medicineList.stream().map(MmsMedicine::getId).collect(Collectors.toList());
                if (!medicineIdList.isEmpty()) {
                    stockLambdaQueryWrapper.in(MmsMedicineStockLog::getMedicineId, medicineIdList);
                } else {
                    stockLambdaQueryWrapper.in(MmsMedicineStockLog::getMedicineId, "");
                }

            } else {
                stockLambdaQueryWrapper.in(MmsMedicineStockLog::getMedicineId, "");
            }
        }
        if (!isNullOrEmpty(startDate)) {
            stockLambdaQueryWrapper.ge(MmsMedicineStockLog::getCreateTime, startDate);
        }
        if (!isNullOrEmpty(endDate)) {
            stockLambdaQueryWrapper.le(MmsMedicineStockLog::getUpdateTime, endDate);
        }
        if (!isNullOrEmpty(stockType)) {
           stockLambdaQueryWrapper.eq(MmsMedicineStockLog::getStockType,stockType);
        }

        if (!isNullOrEmpty(stockId)) {
            stockLambdaQueryWrapper.eq(MmsMedicineStockLog::getStockId,stockId);
        }
        medicineStockLogMapper.selectPage(page, stockLambdaQueryWrapper);
        List<MmsMedicineStockDetailResp> stockDetailList = page.getRecords()
                .stream()
                .map(mmsMedicineLogStock -> {
                    MmsMedicineStockDetailResp medicineStockDetailResp = new MmsMedicineStockDetailResp();
                    MmsMedicineDetailResp medicineDetailResp = new MmsMedicineDetailResp();
                    BeanUtils.copyProperties(mmsMedicineLogStock, medicineStockDetailResp);
                    medicineDetailResp.setCommonNames(mmsMedicineLogStock.getMedicineName());
                    medicineDetailResp.setMedicineCode(mmsMedicineLogStock.getMedicineCode());
                    //入库
                    if (mmsMedicineLogStock.getStockType() == STOCK_IN) {
                        medicineStockDetailResp.setStockQuantity(mmsMedicineLogStock.getIncomeQuantity());
                        //出库
                    } else if (mmsMedicineLogStock.getStockType() == STOCK_OUT) {
                        medicineStockDetailResp.setStockQuantity(mmsMedicineLogStock.getOutQuantity());
                    }

                    MmsMedicineStock mmsMedicineStock = medicineStockMapper.selectById(mmsMedicineLogStock.getStockId());
                    if (!isNullOrEmpty(mmsMedicineStock)) {
                        BeanUtils.copyProperties(mmsMedicineStock, medicineStockDetailResp);
                    }

                    //创建人信息
                    MmsUser user = userMapper.selectById(mmsMedicineLogStock.getUserId());
                    if (!isNullOrEmpty(user)) {
                        MmsMedicineUserResp userResp = new MmsMedicineUserResp();
                        BeanUtils.copyProperties(user, userResp);
                        medicineStockDetailResp.setUserInfo(userResp);
                    }

                    //药品信息
                    medicineStockDetailResp.setMedicineDetailResp(medicineDetailResp);

                    return medicineStockDetailResp;
                })
                .collect(Collectors.toList());
        int total = (int) page.getTotal();
        return CommonResult.success(stockDetailList, total);
    }

    @Override
    @Async
    public Future<ResponseResult> exportMedicineStock(MmsMedicineStockExportReq req, HttpServletResponse response) {
        try {
            LambdaQueryWrapper<MmsMedicineStock> medicineStockLambdaQueryWrapper = new LambdaQueryWrapper<>();
            //药品名称
            if (req.getStockIdList() != null && req.getStockIdList().size() > 0) {
                medicineStockLambdaQueryWrapper.in(MmsMedicineStock::getId, req.getStockIdList());
            }
            if (!isNullOrEmpty(req.getCommonName())) {
                List<String> medicineIdList = medicineMapper.selectList(new LambdaQueryWrapper<MmsMedicine>()
                        .like(MmsMedicine::getCommonNames, req.getCommonName()))
                        .stream().map(MmsMedicine::getId).collect(Collectors.toList());
                if (!medicineIdList.isEmpty()) {
                    medicineStockLambdaQueryWrapper.in(MmsMedicineStock::getMedicineId, medicineIdList);
                }
            }
            if (!isNullOrEmpty(req.getMedicineCode())) {
                List<String> medicineIdList = medicineMapper.selectList(new LambdaQueryWrapper<MmsMedicine>()
                        .like(MmsMedicine::getMedicineCode, req.getMedicineCode()))
                        .stream().map(MmsMedicine::getId).collect(Collectors.toList());
                if (!medicineIdList.isEmpty()) {
                    medicineStockLambdaQueryWrapper.in(MmsMedicineStock::getMedicineId, medicineIdList);
                }
            }
            if (!isNullOrEmpty(req.getStartDate())) {
                medicineStockLambdaQueryWrapper.ge(MmsMedicineStock::getCreateTime, req.getStartDate());
            }
            if (!isNullOrEmpty(req.getEndDate())) {
                medicineStockLambdaQueryWrapper.le(MmsMedicineStock::getUpdateTime, req.getEndDate());
            }
            medicineStockLambdaQueryWrapper.orderByDesc(MmsMedicineStock::getCreateTime);
            List<MmsMedicineStock> medicineStockList = medicineStockMapper.selectList(medicineStockLambdaQueryWrapper);

            List<MmsMedicineStockExportResp> list = medicineStockList.stream().map(mmsMedicineStock -> {
                MmsMedicineStockExportResp medicineStockExportResp = new MmsMedicineStockExportResp();
                BeanUtils.copyProperties(mmsMedicineStock, medicineStockExportResp);
                MmsMedicine medicine = medicineMapper.selectById(mmsMedicineStock.getMedicineId());
                if (!isNullOrEmpty(medicine)) {
                    medicineStockExportResp.setMedicineCode(medicine.getMedicineCode());
                    medicineStockExportResp.setMedicineName(medicine.getCommonNames());
                }
                return medicineStockExportResp;
            }).collect(Collectors.toList());

            //表头数据
            String[] header = req.getLimitColumn().toArray(new String[0]);
            double sheetNum;
            //声明一个工作簿
            HSSFWorkbook workbook = new HSSFWorkbook();
            if (list != null && list.size() > 0) {
                sheetNum = Math.ceil((double) list.size() / PER_SHEET_NUM);
                for (int k = 0; k < sheetNum; k++) {
                    //生成一个表格，设置表格名称为"资源导出表"
                    HSSFSheet sheet = workbook.createSheet("药品库存信息模版导出表" + (k + 1));

                    //设置表格列宽度为10个字节
                    sheet.setDefaultColumnWidth(12);
                    //创建标题的显示样式
                    HSSFCellStyle headerStyle = workbook.createCellStyle();
                    headerStyle.setFillForegroundColor(IndexedColors.YELLOW.index);
                    headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

                    HSSFFont f = workbook.createFont();
                    f.setFontHeightInPoints((short) 10);//字号
                    f.setBold(true);//加粗
                    headerStyle.setFont(f);
                    //创建第一行表头
                    HSSFRow headrow = sheet.createRow(0);

                    //遍历添加表头(下面模拟遍历学生，也是同样的操作过程)
                    for (int i = 0; i < header.length + 1; i++) {
                        //创建一个单元格
                        HSSFCell cell = headrow.createCell(i);

                        if (i == 0) {
                            //创建一个内容对象
                            HSSFRichTextString text = new HSSFRichTextString("序号");
                            //将内容对象的文字内容写入到单元格中
                            cell.setCellValue(text);
                            cell.setCellStyle(headerStyle);
                            continue;
                        }
                        //创建一个内容对象
                        String header1 = apiModelUtil.getFieldValueByFieldName(MmsMedicineStockExportResp.class, header[i - 1]);
                        HSSFRichTextString text = new HSSFRichTextString(header1);

                        //将内容对象的文字内容写入到单元格中
                        cell.setCellValue(text);
                        cell.setCellStyle(headerStyle);
                    }


                    int range = PER_SHEET_NUM;
                    if (k + 1 == sheetNum) {
                        range = list.size() - (PER_SHEET_NUM) * k;
                    }
                    for (int i = 0; i < range; i++) {
                        //创建一行
                        HSSFRow row1 = sheet.createRow(i + 1);
                        MmsMedicineStockExportResp medicineStock = list.get((PER_SHEET_NUM) * k + i);
                        Map map = JSONObject.parseObject(JSON.toJSONString(medicineStock), Map.class);
                        row1.createCell(0).setCellValue(new HSSFRichTextString(i + 1 + ""));
                        for (int j = 0; j < header.length; j++) {
                            String rowContent = "";
                            if(!isNullOrEmpty(map.get(header[j]))) {
                                //创建人
                                if (header[j].equals("medicineId")) {
                                    MmsMedicine medicine = medicineMapper.selectById(medicineStock.getMedicineId());
                                    if (medicine != null) {
                                        rowContent = medicine.getCommonNames();
                                    } else {
                                        rowContent = "";
                                    }
                                    //库存
                                } else if (header[j].equals("stockQuantity")) {
                                    rowContent = "";
                                } else {
                                    rowContent = String.valueOf(map.get(header[j]));
                                }
                            }
                            row1.createCell(j + 1).setCellValue(new HSSFRichTextString(rowContent));
                        }

                    }
                }
            }

            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("药品库存信息模版导出表.xlsx", "utf-8"));
            response.setCharacterEncoding("utf-8");
            response.setHeader("file-type", "download");
            response.setHeader("file-name", URLEncoder.encode("药品库存信息模版导出表.xlsx", "utf-8"));
            response.setHeader("Access-Control-Expose-Headers", "file-type,file-name");
            //刷新缓冲
            response.flushBuffer();
            //workbook将Excel写入到response的输出流中，供页面下载
            OutputStream os = response.getOutputStream();
            workbook.write(os);

            workbook.close();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));
        }
        return null;
    }

    @Override
    @Async
    public Future<ResponseResult> batchMedicineStock(Map<String, Object> map, String user_id) {
        JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(map));
        List<MmsMedicineStockExportResp> medicinesStockBatchReqs = JSONObject.parseArray(JSON.toJSONString(jsonObject.get("list")), MmsMedicineStockExportResp.class);
        if (medicinesStockBatchReqs == null || medicinesStockBatchReqs.size() < 1) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
        }

        //创建导入任务
        MmsImportTask smsImportTask = new MmsImportTask();
        smsImportTask.setTaskName(TASK_NAME_MEDICINE_STOCK_IMPORT);
        smsImportTask.setUserId(user_id);
        smsImportTask.setTaskType(TASK_TYPE_MEDICINE_STOCK);
        mmsImportTaskMapper.insert(smsImportTask);
        batchAddMedicineStockInfo(medicinesStockBatchReqs, smsImportTask.getId(),user_id);
        return new AsyncResult<>(CommonResult.success());
    }

    private void batchAddMedicineStockInfo(List<MmsMedicineStockExportResp> medicineStockBatchReqs, String id,String userId) {

        int OFFSET_ROW = 1;
        int task_status = TASK_STATUS_DONE;
        for (int i = 0; i < medicineStockBatchReqs.size(); i++) {
            //开启事务
            DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
            // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
            dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            // 设置嵌套事务
            TransactionStatus status = transactionManager.getTransaction(dt);
            try {
                MmsMedicineStockExportResp storage = medicineStockBatchReqs.get(i);
                if (isNullOrEmpty(storage.getMedicineCode(),storage.getStockQuantity(),storage.getMedicineUnit())) {
                    transactionManager.rollback(status);
                    task_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(id, REASON_INVALID_PARAM, (i + OFFSET_ROW) + "");
                    continue;
                }
                String medicineCode = storage.getMedicineCode();
                List<MmsMedicine> medicines = medicineMapper.selectList(new LambdaQueryWrapper<MmsMedicine>()
                        .eq(MmsMedicine::getMedicineCode, medicineCode));
                if (medicines.isEmpty()) {
                    transactionManager.rollback(status);
                    task_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(id, REASON_MEDICINE_NOT_EXIST, (i + OFFSET_ROW) + "");
                    continue;
                }
                String medicineId = medicines.get(0).getId();
                List<MmsMedicineStock> medicineStockList = medicineStockMapper.selectList(new LambdaQueryWrapper<MmsMedicineStock>()
                        .eq(MmsMedicineStock::getMedicineId, medicineId));

                //存入库存记录
                MmsMedicineStockLog medicineStockLog = new MmsMedicineStockLog();

                //添加库存
                if (medicineStockList.isEmpty()) {
                    MmsMedicineStock addMedicineStock = new MmsMedicineStock();
                    addMedicineStock.setStockQuantity(storage.getStockQuantity());
                    addMedicineStock.setMedicineUnit(storage.getMedicineUnit());
                    addMedicineStock.setRemarks(storage.getRemarks());
                    addMedicineStock.setMedicineId(medicineId);
                    addMedicineStock.setUserId(userId);
                    medicineStockMapper.insert(addMedicineStock);

                    //记录
                    BeanUtils.copyProperties(addMedicineStock,medicineStockLog,"id");
                    medicineStockLog.setStockId(addMedicineStock.getId());
                    //添加库存数
                }else {
                    MmsMedicineStock updateMedicineStock = new MmsMedicineStock();
                    //原库存数
                    Integer oldStockQuantity = medicineStockList.get(0).getStockQuantity();
                    //增加后的库存数
                    int stockQuantity = oldStockQuantity + storage.getStockQuantity();
                    updateMedicineStock.setStockQuantity(stockQuantity);
                    updateMedicineStock.setMedicineUnit(storage.getMedicineUnit());
                    updateMedicineStock.setRemarks(storage.getRemarks());
                    updateMedicineStock.setMedicineId(medicineId);
                    updateMedicineStock.setUserId(userId);
                    medicineStockMapper.update(updateMedicineStock,new LambdaQueryWrapper<MmsMedicineStock>()
                    .eq(MmsMedicineStock::getMedicineId,medicineId));

                    //记录
                    BeanUtils.copyProperties(updateMedicineStock,medicineStockLog,"id");
                    medicineStockLog.setStockId(updateMedicineStock.getId());
                }

                //存入库存记录
                medicineStockLog.setMedicineId(medicineId);
                medicineStockLog.setMedicineName(medicines.get(0).getCommonNames());
                medicineStockLog.setStockType(STOCK_IN);
                medicineStockLog.setIncomeDate(new Date());
                medicineStockLog.setIncomeQuantity(storage.getStockQuantity());
                medicineStockLog.setUserId(userId);
                medicineStockLogMapper.insert(medicineStockLog);
                transactionManager.commit(status);
            } catch (Exception e) {
                transactionManager.rollback(status);
                task_status = TASK_STATUS_ERR;
                createTeacherImportTaskDetail(id, REASON_IMPORT_ERR, (i + OFFSET_ROW) + "");
            }finally {
                if (status.isNewTransaction() && !status.isCompleted()) {
                    transactionManager.commit(status);
                }
            }
        }
        MmsImportTask smsImportTask = new MmsImportTask();
        smsImportTask.setId(id);
        smsImportTask.setStatus(task_status);
        mmsImportTaskMapper.updateById(smsImportTask);
    }

    private void createTeacherImportTaskDetail(String id, String reason, String row) {
        MmsImportTaskDetail smsImportTaskDetail = new MmsImportTaskDetail();
        smsImportTaskDetail.setTaskId(id);
        smsImportTaskDetail.setFailReason(reason);
        smsImportTaskDetail.setFailRow(row);
        mmsImportTaskDetailMapper.insert(smsImportTaskDetail);
    }


    @Override
    @Async
    public Future<ResponseResult> exportMedicineStockLog(MmsMedicineStockLogExportReq req, HttpServletResponse response) {
        try {
            LambdaQueryWrapper<MmsMedicineStockLog> medicineStockLogLambdaQueryWrapper = new LambdaQueryWrapper<>();
            if (!isNullOrEmpty(req.getCommonName())) {
                List<String> medicineIdList = medicineMapper.selectList(new LambdaQueryWrapper<MmsMedicine>()
                        .like(MmsMedicine::getCommonNames, req.getCommonName()))
                        .stream().map(MmsMedicine::getId).collect(Collectors.toList());
                if (!medicineIdList.isEmpty()) {
                    medicineStockLogLambdaQueryWrapper.in(MmsMedicineStockLog::getMedicineId, medicineIdList);
                }
            }
            if (!isNullOrEmpty(req.getStartDate())) {
                medicineStockLogLambdaQueryWrapper.ge(MmsMedicineStockLog::getCreateTime, req.getStartDate());
            }
            if (!isNullOrEmpty(req.getEndDate())) {
                medicineStockLogLambdaQueryWrapper.le(MmsMedicineStockLog::getUpdateTime, req.getEndDate());
            }
            if (!isNullOrEmpty(req.getStockType())) {
                medicineStockLogLambdaQueryWrapper.eq(MmsMedicineStockLog::getStockType, req.getStockType());
            }

            if (req.getStockIdList() != null && req.getStockIdList().size() > 0) {
                medicineStockLogLambdaQueryWrapper.in(MmsMedicineStockLog::getStockId, req.getStockIdList());
            }
            List<MmsMedicineStockLog> list = medicineStockLogMapper.selectList(medicineStockLogLambdaQueryWrapper);
            //表头数据
            String[] header = req.getLimitColumn().toArray(new String[0]);
            double sheetNum;
            //声明一个工作簿
            HSSFWorkbook workbook = new HSSFWorkbook();
            if (list != null && list.size() > 0) {
                sheetNum = Math.ceil((double) list.size() / PER_SHEET_NUM);
                for (int k = 0; k < sheetNum; k++) {
                    //生成一个表格，设置表格名称为"资源导出表"
                    HSSFSheet sheet = workbook.createSheet("药品库存历史记录导出表" + (k + 1));

                    //设置表格列宽度为10个字节
                    sheet.setDefaultColumnWidth(12);
                    //创建标题的显示样式
                    HSSFCellStyle headerStyle = workbook.createCellStyle();
                    headerStyle.setFillForegroundColor(IndexedColors.YELLOW.index);
                    headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

                    HSSFFont f = workbook.createFont();
                    f.setFontHeightInPoints((short) 10);//字号
                    f.setBold(true);//加粗
                    headerStyle.setFont(f);
                    //创建第一行表头
                    HSSFRow headrow = sheet.createRow(0);

                    //遍历添加表头(下面模拟遍历学生，也是同样的操作过程)
                    for (int i = 0; i < header.length + 1; i++) {
                        //创建一个单元格
                        HSSFCell cell = headrow.createCell(i);

                        if (i == 0) {
                            //创建一个内容对象
                            HSSFRichTextString text = new HSSFRichTextString("序号");
                            //将内容对象的文字内容写入到单元格中
                            cell.setCellValue(text);
                            cell.setCellStyle(headerStyle);
                            continue;
                        }
                        //创建一个内容对象
                        String header1 = apiModelUtil.getFieldValueByFieldName(MmsMedicineStockLog.class, header[i - 1]);
                        HSSFRichTextString text = new HSSFRichTextString(header1);

                        //将内容对象的文字内容写入到单元格中
                        cell.setCellValue(text);
                        cell.setCellStyle(headerStyle);
                    }


                    int range = PER_SHEET_NUM;
                    if (k + 1 == sheetNum) {
                        range = list.size() - (PER_SHEET_NUM) * k;
                    }
                    for (int i = 0; i < range; i++) {
                        //创建一行
                        HSSFRow row1 = sheet.createRow(i + 1);
                        MmsMedicineStockLog medicineStockLog = list.get((PER_SHEET_NUM) * k + i);
                        Map map = JSONObject.parseObject(JSON.toJSONString(medicineStockLog), Map.class);
                        row1.createCell(0).setCellValue(new HSSFRichTextString(i + 1 + ""));
                        for (int j = 0; j < header.length; j++) {
                            String rowContent = "";
                            if(!isNullOrEmpty(map.get(header[j]))) {
                                //入库时间
                                if (header[j].equals("incomeDate")) {
                                    Date incomeDate = medicineStockLog.getIncomeDate();
                                    if (!isNullOrEmpty(incomeDate)) {
                                        rowContent = TimeUtil.DateHanZiSimpleFormat(incomeDate);
                                    } else {
                                        rowContent = "";
                                    }
                                    //出库时间
                                } else if (header[j].equals("outDate")) {
                                    Date outDate = medicineStockLog.getOutDate();
                                    if (!isNullOrEmpty(outDate)) {
                                        rowContent = TimeUtil.DateHanZiSimpleFormat(outDate);
                                    } else {
                                        rowContent = "";
                                    }
                                } else if (header[j].equals("userId")) {
                                    MmsUser mmsUser = userMapper.selectById(medicineStockLog.getUserId());
                                    if (!isNullOrEmpty(mmsUser)) {
                                        rowContent = mmsUser.getNickName();
                                    }
                                } else {
                                    rowContent = String.valueOf(map.get(header[j]));
                                }
                            }
                            row1.createCell(j + 1).setCellValue(new HSSFRichTextString(rowContent));
                        }

                    }
                }
            }

            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("药品库存历史记录导出表.xlsx", "utf-8"));
            response.setCharacterEncoding("utf-8");
            response.setHeader("file-type", "download");
            response.setHeader("file-name", URLEncoder.encode("药品库存历史记录导出表.xlsx", "utf-8"));
            response.setHeader("Access-Control-Expose-Headers", "file-type,file-name");
            //刷新缓冲
            response.flushBuffer();
            //workbook将Excel写入到response的输出流中，供页面下载
            OutputStream os = response.getOutputStream();
            workbook.write(os);

            workbook.close();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));
        }
        return null;
    }


}
